package ynu.edu.controller;

import io.github.resilience4j.bulkhead.annotation.Bulkhead;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import ynu.edu.entity.User;
import ynu.edu.feign.ServiceProviderService;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * 隔离器测试控制器
 * 测试并发限制功能
 */
@RestController
@RequestMapping("/bulkhead")
public class BulkheadTestController {

    @Resource
    private ServiceProviderService serviceProviderService;

    /**
     * 主要业务接口 - 使用mainBulkhead（最大并发10，等待20ms）
     */
    @GetMapping("/mainService/{userId}")
    @Bulkhead(name = "mainBulkhead", fallbackMethod = "mainServiceFallback", type = Bulkhead.Type.SEMAPHORE)
    @CircuitBreaker(name = "circuitBreakerA", fallbackMethod = "mainServiceFallback")
    public Map<String, Object> mainService(@PathVariable("userId") Integer userId) {
        // 直接调用远程服务，让JMeter真实测试并发限制
        User user = serviceProviderService.GetUserById(userId);
        System.out.println("隔离器调用成功，返回用户: " + user.getUserName() + " from " + user.getPassWord());
        
        return Map.of(
                "bulkhead", "mainBulkhead",
                "status", "SUCCESS",
                "data", user,
                "timestamp", LocalDateTime.now(),
                "message", "主要业务服务 - 正常执行",
                "threadName", Thread.currentThread().getName()
        );
    }

    /**
     * 主要业务接口的降级方法
     */
    public Map<String, Object> mainServiceFallback(Integer userId, Exception ex) {
        System.out.println("隔离器降级: " + ex.getMessage());
        
        return Map.of(
                "bulkhead", "mainBulkhead",
                "status", "FALLBACK",
                "userId", userId,
                "timestamp", LocalDateTime.now(),
                "error", ex.getMessage(),
                "message", "主要业务服务 - 并发限制或熔断触发，服务降级",
                "reason", ex.getClass().getSimpleName().contains("Bulkhead") ? "并发限制" : "熔断保护"
        );
    }

    /**
     * 测试接口 - 使用testBulkhead（最大并发5，等待20ms）
     */
    @GetMapping("/testService")
    @Bulkhead(name = "testBulkhead", fallbackMethod = "testServiceFallback", type = Bulkhead.Type.SEMAPHORE)
    public Map<String, Object> testService() {
        // 直接调用远程服务
        Map<String, Object> users = serviceProviderService.getAllUsers();
        System.out.println("隔离器调用成功，获取所有用户列表");
        
        return Map.of(
                "bulkhead", "testBulkhead",
                "status", "SUCCESS",
                "data", users,
                "timestamp", LocalDateTime.now(),
                "message", "测试服务 - 正常执行",
                "threadName", Thread.currentThread().getName()
        );
    }

    /**
     * 测试接口的降级方法
     */
    public Map<String, Object> testServiceFallback(Exception ex) {
        System.out.println("隔离器降级: " + ex.getMessage());
        
        return Map.of(
                "bulkhead", "testBulkhead",
                "status", "FALLBACK",
                "timestamp", LocalDateTime.now(),
                "error", ex.getMessage(),
                "message", "测试服务 - 并发限制触发，服务降级",
                "fallbackData", "测试服务暂时不可用，请稍后重试"
        );
    }

    /**
     * 批量处理接口 - 使用batchBulkhead（最大并发3，等待50ms）
     */
    @PostMapping("/batchProcess")
    @Bulkhead(name = "batchBulkhead", fallbackMethod = "batchProcessFallback", type = Bulkhead.Type.SEMAPHORE)
    public Map<String, Object> batchProcess(@RequestBody Map<String, Object> batchData) {
        // 模拟批量处理的长时间操作
        try {
            Thread.sleep(2000); // 2秒处理时间
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        return Map.of(
                "bulkhead", "batchBulkhead",
                "status", "SUCCESS",
                "batchData", batchData,
                "timestamp", LocalDateTime.now(),
                "message", "批量处理服务 - 正常执行",
                "threadName", Thread.currentThread().getName(),
                "processTime", "2000ms",
                "processedItems", batchData.getOrDefault("items", "unknown")
        );
    }

    /**
     * 批量处理的降级方法
     */
    public Map<String, Object> batchProcessFallback(Map<String, Object> batchData, Exception ex) {
        return Map.of(
                "bulkhead", "batchBulkhead",
                "status", "FALLBACK",
                "batchData", batchData,
                "timestamp", LocalDateTime.now(),
                "error", ex.getMessage(),
                "message", "批量处理服务 - 并发限制触发，任务已排队",
                "fallbackAction", "批量任务已记录，将稍后处理"
        );
    }

    /**
     * 并发压力测试接口 - 快速生成大量并发请求
     */
    @GetMapping("/concurrencyTest/{concurrentCount}")
    public Map<String, Object> concurrencyTest(@PathVariable("concurrentCount") Integer concurrentCount) {
        java.util.List<CompletableFuture<Map<String, Object>>> futures = new java.util.ArrayList<>();
        long startTime = System.currentTimeMillis();

        // 创建指定数量的并发请求
        for (int i = 0; i < concurrentCount; i++) {
            final int requestId = i + 1;
            CompletableFuture<Map<String, Object>> future = CompletableFuture.supplyAsync(() -> {
                try {
                    return mainService(requestId);
                } catch (Exception e) {
                    return Map.of(
                            "requestId", requestId,
                            "status", "ERROR",
                            "error", e.getMessage(),
                            "timestamp", LocalDateTime.now()
                    );
                }
            });
            futures.add(future);
        }

        // 等待所有请求完成
        CompletableFuture<Void> allFutures = CompletableFuture.allOf(
                futures.toArray(new CompletableFuture[0])
        );

        try {
            allFutures.get(); // 等待所有完成
        } catch (Exception e) {
            // 处理异常
        }

        // 收集结果
        java.util.List<Map<String, Object>> results = new java.util.ArrayList<>();
        int successCount = 0;
        int fallbackCount = 0;

        for (CompletableFuture<Map<String, Object>> future : futures) {
            try {
                Map<String, Object> result = future.get();
                results.add(result);
                if ("SUCCESS".equals(result.get("status"))) {
                    successCount++;
                } else {
                    fallbackCount++;
                }
            } catch (Exception e) {
                fallbackCount++;
                results.add(Map.of("error", e.getMessage()));
            }
        }

        long endTime = System.currentTimeMillis();

        return Map.of(
                "testType", "并发压力测试",
                "concurrentRequests", concurrentCount,
                "totalTime", (endTime - startTime) + "ms",
                "successCount", successCount,
                "fallbackCount", fallbackCount,
                "results", results,
                "bulkheadConfig", Map.of(
                        "maxConcurrent", 10,
                        "maxWaitTime", "20ms"
                ),
                "explanation", "观察并发限制效果：超过10个并发时应该触发降级"
        );
    }

    /**
     * 隔离器状态查询接口
     */
    @GetMapping("/status")
    public Map<String, Object> getBulkheadStatus() {
        return Map.of(
                "timestamp", LocalDateTime.now(),
                "bulkheadInstances", Map.of(
                        "mainBulkhead", Map.of(
                                "maxConcurrentCalls", 10,
                                "maxWaitDuration", "20ms",
                                "type", "SEMAPHORE"
                        ),
                        "testBulkhead", Map.of(
                                "maxConcurrentCalls", 5,
                                "maxWaitDuration", "20ms",
                                "type", "SEMAPHORE"
                        ),
                        "batchBulkhead", Map.of(
                                "maxConcurrentCalls", 3,
                                "maxWaitDuration", "50ms",
                                "type", "SEMAPHORE"
                        )
                ),
                "testEndpoints", java.util.List.of(
                        "GET /bulkhead/mainService/{userId}",
                        "GET /bulkhead/testService",
                        "POST /bulkhead/batchProcess",
                        "GET /bulkhead/concurrencyTest/{count}"
                )
        );
    }
} 